﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using RGBGame.VisualJSApp;
using VisualJS.Web.Forms;
using MessageBox = VisualJS.Web.Forms.MessageBox;
using Panel = VisualJS.Web.Forms.Panel;
using PictureBox = VisualJS.Web.Forms.PictureBox;

namespace RGBGame
{
    public class GameTools:GameLogic
    {
        internal MainForm gameForm;
        internal bool AIPlayer;
        internal PictureBox[] tiles = new PictureBox[36];
        internal Panel gameHost = new Panel();
        internal int cellsFilled = 0;
        internal string opponentsId = "";
        internal int w, h;
        internal bool rendered = false;

        public GameTools(MainForm frm, bool aiPlayer=false)
        {
            AIPlayer = aiPlayer;
            rgbSub = this;
            gameForm = frm;

            for (int x = 0; x < 6; x++)
            {
                tileStatus[x] = new Colors[6];
            }

            if(AIPlayer)
            {
                AIRandomCells = new int[36]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35};
                for(int i=0;i<72;i++)
                {
                    int n = (Utility.getRandom() % 36);
                    int q = AIRandomCells[n];
                    AIRandomCells[n] = AIRandomCells[i%36];
                    AIRandomCells[i%36] = q;
                }
            }
            else
            {
                int i = 36;
                while (i-- > 0)
                {
                    tiles[i] = new PictureBox();
                    tiles[i].Name = "box_" + i.ToString();
                    tiles[i].BorderStyle = BorderStyle.FixedSingle;
                    tiles[i].BorderLineStyle = Panel.ClientBorderStyle.Dotted;
                    tiles[i].BorderColor = "#999999".ToColor();
                    tiles[i].MouseDown += new MouseEventHandler(MouseDown);
                    gameHost.Controls.Add(tiles[i]);
                }
            }
        }

        internal void resetGame()
        {
            if (AIPlayer)
                return;

            cellsFilled = 0;
            clearTiles();
            gameHost.Enabled = false;
            opponentsId = "";
            myScore = 0;
            opScore = 0;
            updateScores();
        }

        internal void clearTiles()
        {
            for (int x = 0; x < 6; x++)
                for (int y = 0; y < 6; y++)
                    tileStatus[x][y] = Colors.Transparent;

            int i = 36;
            while (i-- > 0)
            {
                tiles[i].BackColor = Color.Transparent;
                tiles[i].Opacity = 100;
            }
        }
        
        internal void updatePlayerColors()
        {
            if (AIPlayer)
                return;

            gameForm.lblMyColor.BackColor = Utility.getColor(MyColor);
            gameForm.lblOpColor.BackColor = Utility.getColor(OpColor);
        }

        public void GameEvent(NotificationReason reason, object gameData)
        {
            switch (reason)
            {
                case NotificationReason.JoinGame:
                    {
                        object[] data = (object[])gameData;
                        opponentsId = data[0].ToString();
                        int order = (int)data[1];
                        myTurn = order;
                        if (order == 1)
                            opTurn = 2;
                        else
                        {
                            opTurn = 1;
                        }

                        updatePlayerColors();
                        highlightInfo("Game has started<br/>Waiting for other player to play...", true);
                    }
                    break;
                case NotificationReason.YourTurn:
                    {
                        if (gameData != null)
                        {
                            object[] data = (object[])gameData;
                            int tileId = (int)data[0];

                            opTurn = (int)data[1];//current turn of opponent
                            markTile(tileId, OpColor);

                            opTurn = (int)data[2];//next turn of opponent
                            updatePlayerColors();
                        }
                        
                        if (!AIPlayer)
                            gameHost.Enabled = true;
                        else
                        {
                            playTurn(MyColor);
                        }

                        hideInfo();
                        break;
                    }
                case NotificationReason.EndGame:
                case NotificationReason.EndGameOpponentExit:
                    {
                        if (AIPlayer)
                        {
                            Room.RemovePlayer("AI_" + opponentsId);
                            return;
                        }

                        bool crossSession = (bool)gameData;

                        resetGame();

                        if (!crossSession)
                        {
                            highlightInfo("The player has left the game!", true, true);
                        }
                        else
                        {
                            VisualJS.Web.Forms.MessageBox.Show("Warning!", "You have opened a new game on same browser instance!<br/>When you click OK the other instance will be closed.", gameForm, delegate(MessageBoxResult result)
                            {
                                Utility.BindSession(gameForm.SessionID, gameForm.ClientID);
                                highlightInfo("Welcome to VisualJS.NET's RGB Game", true, true);
                            });
                        }
                    }
                    break;
                case NotificationReason.GotScore:
                    {
                        object[] data = (object[])gameData;
                        opTurn = (int)data[2];
                        paintScore((int)data[0], (int)data[1], false, OpColor);
                        highlightScore("Your opponent got 1 point!", false);
                    }
                    break;
            }
        }

        internal void MouseDown(object sender, MouseEventArgs e)
        {
            if (!gameHost.Enabled)
                return;

            PictureBox box = (PictureBox)sender;

            //access control names from NameTip (box_0 ...) 
            //(VisualJS converts original names to numbers in order reduce client script size and improve security)
            int i = int.Parse(box.NameTip.Split('_')[1]);
            TilePoint xy = TilePoint.get(i);
            Colors ch = tileStatus[xy.X][xy.Y];
            if (ch == Colors.Transparent)
            {
                playTile(i);
            }
        }

        internal void playTile(int i)
        {
            markTile(i, MyColor);
            int result = checkScore(i, MyColor);

            if (result != CELL_NO_MATCH)
            {
                paintScore(result, i, true, MyColor);
                Room.GotScore(gameForm.ClientID, opponentsId, i, result, myTurn, GameEvent);
                highlightScore("You got 1 Point!<br/>Waiting for other player to play", true);
            }
            else
                highlightInfo("Waiting for other player to play!", true, false);

            if (!AIPlayer)
                gameHost.Enabled = false;

            int nextTurn = Utility.getRandom();//get the next turn index
            Room.EndOfTurn(gameForm.ClientID, opponentsId, i, myTurn, nextTurn, GameEvent);

            myTurn = nextTurn;//activate it
            updatePlayerColors();
        }

        internal void gameEndCheck()
        {
            if (cellsFilled == 36)
            {
                if (!AIPlayer)
                {
                    string strGameResult = "You win the game!";
                    if (opScore > myScore)
                        strGameResult = "You lost the game.";
                    else if (opScore == myScore)
                    {
                        strGameResult = "Draw! Nobody won the game.";
                    }

                    MessageBox.Show("Game Over!", strGameResult + "<br/>Would you like to play again?", gameForm, MessageBoxType.YesNo, delegate(MessageBoxResult result)
                    {
                        if (result == MessageBoxResult.Yes)
                        {
                            resetGame();
                            Room.ResetGame(gameForm.ClientID, opponentsId, GameEvent);
                            highlightInfo("You've back in the queue for a next game", true, true);
                        }
                        else
                        {
                            resetGame();
                            highlightInfo("Thanks for playing!", true);
                        }
                    });
                }
                else
                {
                    Room.RemovePlayer("AI_" + gameForm.ClientID);
                }
            }
        }

        internal void updateSizes()
        {
            if (!rendered)
                return;

            w = gameForm.Width - 10;
            w -= 25; // 5 per each empty space or border
            w /= 6;
            h = gameForm.Height - 35;
            h -= 25; // 5 per each empty space or border
            h /= 6;
            
            int i = 36;
            while (i-- > 0)
            {
                TilePoint pos = TilePoint.get(i);
                tiles[i].Location = new Point(5 + (pos.X * (w + 5)), 30 + (pos.Y * (h + 5)));
                tiles[i].Size = new Size(w, h);
            }
        }

        internal void DrawTiles()
        {
            if(rendered)
                return;

            rendered = true;

            gameHost.Name = "gameHost";
            gameHost.Location = new Point(0, 30);
            gameHost.Dock = DockStyle.Fill;

            updateSizes();

            gameHost.Enabled = false;
            gameForm.mainPanel.Controls.Add(gameHost);
        }

        internal bool waitForHide = false;
        internal void highlightScore(string text, bool self)
        {
            if (AIPlayer)
                return; 

            gameForm.pnlInfo.Visible = true;
            gameForm.lblKeep.Text = text;

            if (self)
            {
                gameForm.pnlInfo.BackColor = Color.YellowGreen;
                gameForm.pnlInfo.BackColorEnd = Color.Gold;
            }
            else
            {
                gameForm.pnlInfo.BackColor = "#a00000".ToColor();
                gameForm.pnlInfo.BackColorEnd = Color.Transparent;
            }

            waitForHide = true;//wait some time to show other player got score!
        }

        internal void highlightInfo(string text, bool showPlayAlone=false, bool showMulti = false)
        {
            if (AIPlayer)
                return;

            gameForm.pnlInfo.BackColor = "#222222".ToColor();
            gameForm.pnlInfo.BackColorEnd = Color.Transparent;
            gameForm.pnlInfo.Visible = true;
            gameForm.lblKeep.Text = text;

            gameForm.lblSingle.Visible = showPlayAlone;
            gameForm.lblTut.Visible = showPlayAlone;
            gameForm.lblMulti.Visible = showMulti;
        }

        internal void hideInfo()
        {
            if (AIPlayer)
                return;

            if (waitForHide)
            {
                gameForm.pnlInfo.HideAfterWait(1500);
                waitForHide = false;
            }
            else
            {
                gameForm.pnlInfo.Visible = false;
            }
        }

        internal void paintScore(int result, int i, bool self, Colors ch)
        {
            Color clr = Utility.getColor(ch);
            int[] ids = GameLogic.scoreCells(i, result);

            for (int j = 0; j < 3; j++)
            {
                int n = ids[j];
                if (!AIPlayer)
                {
                    tiles[n].Opacity = 20;
                    tiles[n].BackColor = clr;
                }

                TilePoint pos = TilePoint.get(n);

#if DEBUG
                if (tileStatus[pos.X][pos.Y] == Colors.ScoredOpponent || tileStatus[pos.X][pos.Y] == Colors.ScoredYou)
                    Debugger.Break();
#endif 
                if (self)
                {
                    tileStatus[pos.X][pos.Y] = Colors.ScoredYou;
                }
                else
                {
                    tileStatus[pos.X][pos.Y] = Colors.ScoredOpponent;
                }
            }

            if (self)
                myScore++;
            else
            {
                opScore++;
            }

            updateScores();
        }

        internal void updateScores()
        {
            if (AIPlayer)
                return;

            gameForm.lbScore1.Text = myScore.ToString("D2");
            gameForm.lbScore2.Text = opScore.ToString("D2");
        }
    }
}